#pragma once
#include <iostream>
#include <queue>
#include <string>
#include <mutex>
#include <pthread.h>
#include <string.h>
#include <time.h>
#include <unordered_map>
#include "./log/log.hpp"
#include "connector/include/mysql.h"
#define HOST "localhost"
#define SOCKET "/var/lib/mysql/mysql.sock"

class MysqlPool
{
public:
    static MysqlPool *GetInstance(int connectNum, std::string username, std::string password, std::string database)
    {
        MaxNum = connectNum;
        if (instance == nullptr)
        {
            mtx_.lock();
            if (instance == nullptr)
            {
                instance = new MysqlPool(connectNum, username, password, database);
            }
            mtx_.unlock();
        }
        return instance;
    }
    MYSQL *GetConnection()
    {
        mtx_.lock();
        if (!MysqlQueue.empty())
        {
            MYSQL *con = MysqlQueue.front();
            MysqlQueue.pop();
            std::string num(std::to_string(MysqlQueue.size()));
            LOG(NOTICE, "MysqlQueue size: " + num);
            if ((time(nullptr) - last_use_time[con]) > 4 * 3600)
            {
                LOG(NOTICE,"time out");
                // 如果超时，从Map中删除该连接
                last_use_time.erase(con);
                mysql_close(con);
                delete con;
            }
            else
            {
                // 更新最后一次使用连接时间
                last_use_time[con] = time(nullptr);
                mtx_.unlock();
                return con;
            }
        }
        MYSQL *con = new MYSQL;
        mysql_init(con);
        if (con != nullptr)
        {
            if (mysql_real_connect(con, HOST, username_.c_str(), password_.c_str(), database_.c_str(), 0, SOCKET, 0) == nullptr)
            {
                mysql_close(con);
                delete con;
                mtx_.unlock();
                return nullptr;
            }
            // // 创建连接成功，如果队列未满,入队并且Map中插入该连接
            // if (MysqlQueue.size() < MaxNum)
            // {
            //     MysqlQueue.push(con);
            //     last_use_time[con] = time(nullptr);
            // }
        }
        mtx_.unlock();
        return con;
    }

    void ReleaseCon(MYSQL *con)
    {
        if (con != nullptr)
        {
            // std::unique_lock<std::mutex> lock(mtx_);
            mtx_.lock();
            if(MysqlQueue.size() < MaxNum)
            {
                last_use_time[con] = time(nullptr);
                MysqlQueue.push(con);
            }
            else{
                mysql_close(con);
                delete con;
            }
            mtx_.unlock();
        }
    }

    ~MysqlPool()
    {
        while (!MysqlQueue.empty())
        {
            MYSQL *con = MysqlQueue.front();
            mysql_close(con);
            delete con;
            MysqlQueue.pop();
        }
    }

private:
    std::string username_;
    std::string password_;
    std::string database_;
    std::queue<MYSQL *> MysqlQueue;
    static MysqlPool *instance;
    static std::mutex mtx_;
    std::unordered_map<MYSQL *, time_t> last_use_time;
    static int MaxNum;

private:
    // 单例模式
    MysqlPool(const MysqlPool &) = delete;
    MysqlPool &operator=(const MysqlPool &) = delete;
    MysqlPool(int connectNum, std::string username, std::string password, std::string database)
        : database_(database), username_(username), password_(password)
    {
        for (int i = 0; i < connectNum; i++)
        {
            MYSQL *con = new MYSQL;
            mysql_init(con);
            if (con != nullptr)
            {
                if (mysql_real_connect(con, HOST, username.c_str(), password.c_str(), database.c_str(), 0, SOCKET, 0) != nullptr)
                {
                    mysql_options(con, MYSQL_SET_CHARSET_NAME, "utf8mb4");
                    last_use_time[con] = time(nullptr);
                    MysqlQueue.push(con);
                }
                else
                {
                    LOGERR("Connect Failed!");
                }
            }
        }
    }
};
MysqlPool *MysqlPool::instance = nullptr;
std::mutex MysqlPool::mtx_;
int MysqlPool::MaxNum = 0;